package enterpriseapp.hibernate;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.apache.commons.beanutils.BasicDynaBean;
import org.apache.commons.beanutils.BasicDynaClass;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.hibernate.internal.CriteriaImpl.Subcriteria;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.Type;
import com.vaadin.data.Item;
import com.vaadin.data.hbnutil.ContainerFilter;
import enterpriseapp.Utils;
import enterpriseapp.hibernate.annotation.CrudTable;
import enterpriseapp.ui.Constants;
/**
* Container based on HbnContainer add-on (https://vaadin.com/directory#addon/hbncontainer).
*
* @author Alejandro Duarte
*
* @param <T> Entity (Dto) type.
*/
@SuppressWarnings("unchecked")
public class DefaultHbnContainer<T> extends CustomHbnContainer<T> {
private static final long serialVersionUID = 1L;
/**
* Constructor.
* @param clazz Entity class.
*/
public DefaultHbnContainer(Class<T> clazz) {
super(clazz, Db.getCurrentSession().getSessionFactory());
}
/**
* @return a new Entity instance.
*/
public T newInstance() {
T newInstance = null;
try {
newInstance = entityType.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
return newInstance;
}
/**
* Returns the Entity with the given id.
* @param id Entity's id to load.
* @return the Entity with the given id or null if not found.
*/
public T getEntity(Serializable id) {
return (T) sessionFactory.getCurrentSession().get(entityType, id);
}
/**
* @return the number of Entities in this container.
*/
public long count() {
return (Long) singleSpecialQuery("select count(id) from " + entityType.getSimpleName());
}
@Override
public boolean removeItem(Object itemId) throws UnsupportedOperationException {
boolean result = super.removeItem(itemId);
sessionFactory.getCurrentSession().getTransaction().commit();
sessionFactory.getCurrentSession().beginTransaction();
return result;
}
/**
* Removes all items in the container.
*/
public boolean removeAllItems() throws UnsupportedOperationException {
update("delete from " + entityType.getSimpleName());
return true;
}
/**
* Adds a new Entity to the container and returns an EntityItem.
* @param itemId Entity to add.
* @return A new EntityItem containing the added Entity.
*/
@SuppressWarnings("rawtypes")
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
T dto = (T) saveOrUpdateEntity((T) itemId);
return new EntityItem((Serializable) dto);
}
/**
* Override this to add custom behavior before an Entity is saved or updated.
* @param entity the Entity being saved or updated.
*/
public void beforeSaveOrUpdate(T entity) {
}
/**
* Override this to add custom behavior after an Entity is saved or updated.
* @param entity the Entity being saved or updated.
*/
public void afterSaveOrUpdate(T entity) {
}
/**
* Saves or update the given Entity.
* @param entity Entity to save or update.
* @return id for the saved Entity.
*/
public Serializable saveOrUpdateEntity(T entity) {
beforeSaveOrUpdate(entity);
entity = (T) sessionFactory.getCurrentSession().merge(entity);
sessionFactory.getCurrentSession().saveOrUpdate(entity);
clearInternalCache();
fireItemSetChange();
afterSaveOrUpdate(entity);
return (Serializable) getIdForPojo(entity);
}
/**
* Saves the given Entity.
* @param entity Entity to save.
* @return id for the saved Entity.
*/
@Override
public Serializable saveEntity(T entity) {
sessionFactory.getCurrentSession().save(entity);
clearInternalCache();
fireItemSetChange();
return (Serializable) getIdForPojo(entity);
}
/**
* Gets all the Entities in the container.
* @return all Entities in the container.
*/
public List<T> listAll() {
Criteria crit = getCriteria();
return crit.list();
}
/**
* Executes the given query.
* @param query query to execute.
* @return Entity returned by the query (null if no result found).
*/
protected T singleQuery(String query) {
return singleQuery(query, null);
}
/**
* Executes the given query with the given parameters.
* @param query query to execute.
* @param params query parameters.
* @return Entity returned by the query (null if no result found).
*/
protected T singleQuery(String query, Object[] params) {
List<T> list = query(query, params);
if(list != null && !list.isEmpty()) {
return list.get(0);
}
return null;
}
/**
* Executes the given query with the given parameters by name.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
* @return Entity returned by the query (null if no result found).
*/
protected T singleQuery(String query, String[] paramNames, Object[] params) {
return query(query, paramNames, params).get(0);
}
/**
* Executes the given query.
* @param query query to execute.
* @return List of Entities returned by the query).
*/
protected List<T> query(String query) {
return query(query, null);
}
/**
* Executes the given query with the given parameters.
* @param query query to execute.
* @param params query parameters.
* @return List of Entities returned by the query.
*/
protected List<T> query(final String query, final Object[] params) {
Query q = sessionFactory.getCurrentSession().createQuery(query);
if(params != null) {
for(int i = 0; i < params.length; i++) {
q.setParameter(i, params[i]);
}
}
List<T> list = q.list();
return list;
}
/**
* Executes the given query with the given parameters by name.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
* @return List of Entities returned by the query.
*/
protected List<T> query(final String query, final String[] paramNames, final Object[] params) {
return query(query, paramNames, params, null, null);
}
/**
* Executes the given query with the given parameters by name.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
* @param collectionParamNames parameters' names for parameters of type Collection.
* @param collectionParams query parameters of type Collection.
* @return List of Entities returned by the query.
*/
protected List<T> query(final String query, final String[] paramNames, final Object[] params, final String[] collectionParamNames, Collection<?>[] collectionParams) {
return query(query, paramNames, params, collectionParamNames, collectionParams, null, null);
}
/**
* Executes the given query with the given parameters by name.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
* @param collectionParamNames parameters' names for parameters of type Collection.
* @param collectionParams query parameters of type Collection.
* @param maxResults max results to return.
* @param firstResult first result to return.
* @return List of Entities returned by the query.
*/
protected List<T> query(final String query, final String[] paramNames, final Object[] params, final String[] collectionParamNames, Collection<?>[] collectionParams, Integer maxResults, Integer firstResult) {
Query q = getQuery(query, paramNames, params, collectionParamNames, collectionParams, maxResults, firstResult);
List<T> list = q.list();
return list;
}
/**
* Executes the given query.
* @param query query to execute.
* @return result of the query (type defined by the query select clause).
*/
protected Object singleSpecialQuery(final String query) {
List<?> result = specialQuery(query);
return result != null && result.size() > 0 ? result.get(0) : null;
}
/**
* Executes the given query with the given parameters.
* @param query query to execute.
* @param params query parameters.
* @return result of the query (type defined by the query select clause).
*/
protected Object singleSpecialQuery(final String query, final Object[] params) {
List<?> result = specialQuery(query, params);
return result != null && result.size() > 0 ? result.get(0) : null;
}
/**
* Executes the given query.
* @param query query to execute.
* @return List of results of the query (type defined by the query select clause).
*/
protected List<?> specialQuery(final String query) {
return specialQuery(query, null);
}
/**
* Executes the given query.
* @param query query to execute.
* @param params query parameters.
* @return List of results of the query (type defined by the query select clause).
*/
@SuppressWarnings("rawtypes")
protected List specialQuery(final String query, final Object[] params) {
Query q = sessionFactory.getCurrentSession().createQuery(query);
if(params != null) {
for(int i = 0; i < params.length; i++) {
q.setParameter(i, params[i]);
}
}
List list = q.list();
return list;
}
/**
* Executes the given query.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
* @return List of results of the query (type defined by the query select clause).
*/
@SuppressWarnings("rawtypes")
protected List specialQuery(final String query, final String[] paramNames, final Object[] params) {
Query q = sessionFactory.getCurrentSession().createQuery(query);
if(params != null) {
for(int i = 0; i < params.length; i++) {
q.setParameter(paramNames[i], params[i]);
}
}
List list = q.list();
return list;
}
/**
* Executes the given query.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
* @param collectionParamNames parameters' names for parameters of type Collection.
* @param collectionParams query parameters of type Collection.
* @return List of results of the query (type defined by the query select clause).
*/
@SuppressWarnings("rawtypes")
protected List specialQuery(final String query, final String[] paramNames, final Object[] params, final String[] collectionParamNames, Collection<?>[] collectionParams) {
return specialQuery(query, paramNames, params, collectionParamNames, collectionParams, null, null);
}
/**
* Executes the given query.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
* @param collectionParamNames parameters' names for parameters of type Collection.
* @param collectionParams query parameters of type Collection.
* @param maxResults max results to return.
* @param firstResult first result to return.
* @return List of results of the query (type defined by the query select clause).
*/
@SuppressWarnings("rawtypes")
protected List specialQuery(final String query, final String[] paramNames, final Object[] params, final String[] collectionParamNames, Collection<?>[] collectionParams, Integer maxResults, Integer firstResult) {
Query q = getQuery(query, paramNames, params, collectionParamNames, collectionParams, maxResults, firstResult);
List list = q.list();
return list;
}
/**
* Executes the given query.
* @param query query to execute.
*/
public void update(final String query) {
getQuery(query, null, null, null, null, null, null).executeUpdate();
}
/**
* Executes the given query.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
*/
public void update(final String query, final Object[] params) {
getQuery(query, null, params, null, null, null, null).executeUpdate();
}
/**
* Executes the given query.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
*/
public void update(final String query, final String[] paramNames, final Object[] params) {
getQuery(query, paramNames, params, null, null, null, null).executeUpdate();
}
/**
* Executes the given query.
* @param query query to execute.
* @param paramNames parameters' names in the query.
* @param params query parameters.
* @param collectionParamNames parameters' names for parameters of type Collection.
* @param collectionParams query parameters of type Collection.
*/
public void update(final String query, final String[] paramNames, final Object[] params, final String[] collectionParamNames, Collection<?>[] collectionParams) {
getQuery(query, paramNames, params, collectionParamNames, collectionParams, null, null).executeUpdate();
}
/**
* Constructs a Query object.
* @param query query text.
* @param paramNames parameters' names in the query (if null, positional binding is used).
* @param params query parameters.
* @param collectionParamNames parameters' names for parameters of type Collection.
* @param collectionParams query parameters of type Collection.
* @param maxResults max results to return.
* @param firstResult first result to return.
* @return Query object.
*/
public Query getQuery(final String query, final String[] paramNames, final Object[] params, final String[] collectionParamNames, Collection<?>[] collectionParams, Integer maxResults, Integer firstResult) {
Query q = sessionFactory.getCurrentSession().createQuery(query);
if(maxResults != null) {
q.setMaxResults(maxResults);
}
if(firstResult != null) {
q.setFirstResult(firstResult);
}
if(paramNames != null) {
if(params != null) {
for(int i = 0; i < params.length; i++) {
q.setParameter(paramNames[i], params[i]);
}
}
} else {
if(params != null) {
for(int i = 0; i < params.length; i++) {
q.setParameter(i, params[i]);
}
}
}
if(collectionParams != null) {
for(int i = 0; i < collectionParams.length; i++) {
q.setParameterList(collectionParamNames[i], collectionParams[i]);
}
}
return q;
}
/**
* Converts the special query result to a DynaBean collection. This method is useful to create reports from
* special queries.
* @param result result returned by "specialQuery" methods.
* @param properties properties for the beans to create.
* @param classes property types.
* @return a collection of dynamic beans.
*/
public Collection<?> parseSpecialQueryResult(List<?> result, String[] properties, Class<?>[] classes) {
ArrayList<DynaBean> data = new ArrayList<DynaBean>();
for(Object row : result) {
if(Object[].class.isAssignableFrom(row.getClass())) {
data.add(objectArrayToBean((Object[]) row, properties, classes));
} else {
data.add(objectArrayToBean(new Object[] {row}, properties, classes));
}
}
return data;
}
/**
* Constructs a DynaBean using the values and properties specified.
* @param values property values.
* @param properties properties to add to the bean.
* @param classes properties types.
* @return DynBean with the values and properties specified.
*/
protected DynaBean objectArrayToBean(Object[] values, String[] properties, Class<?>[] classes) {
DynaBean dynaBean = null;
try {
DynaProperty[] columnsDynaProperties = getColumnsDynaProperties(properties, classes);
BasicDynaClass clazz = new BasicDynaClass(this.getClass().getSimpleName(), BasicDynaBean.class, columnsDynaProperties);
dynaBean = clazz.newInstance();
for(int i = 0; i < columnsDynaProperties.length; i++) {
dynaBean.set(columnsDynaProperties[i].getName(), values[i]);
}
} catch (Exception e) {
throw new RuntimeException("Error creating dynamic bean", e);
}
return dynaBean;
}
protected DynaProperty[] getColumnsDynaProperties(String[] properties, Class<?>[] classes) {
DynaProperty[] dynaProperties = new DynaProperty[properties.length];
for(int i = 0; i < properties.length; i++) {
dynaProperties[i] = new DynaProperty(properties[i], classes[i]);
}
return dynaProperties;
}
protected ClassMetadata getClassMetadata() {
if (classMetadata == null) {
classMetadata = sessionFactory.getClassMetadata(entityType);
}
return classMetadata;
}
/**
* @return a Criteria object with restrictions accordingly to current filters.
*/
@Override
public Criteria getBaseCriteria() {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(entityType);
ArrayList<Subcriteria> subcriterias = new ArrayList<Subcriteria>();
if (filters != null) {
for (ContainerFilter f : filters) {
StringContainerFilter filter = (StringContainerFilter) f;
String propertyString = filter.getPropertyId().toString();
String[] properties = propertyString.split("\\.");
String property = properties[properties.length - 1];
Type propertyType = getClassMetadata().getPropertyType(properties[0]);
if(properties.length > 1) {
for(int i = 0; i < properties.length - 1; i++) {
boolean subcriteriaFound = false;
for(Subcriteria sc : subcriterias) {
if(sc.getPath().equals(properties[i])) {
criteria = sc;
subcriteriaFound = true;
break;
}
}
if(!subcriteriaFound) {
criteria = criteria.createCriteria(properties[i]);
subcriterias.add((Subcriteria) criteria);
}
propertyType = sessionFactory.getCurrentSession().getSessionFactory().getClassMetadata(propertyType.getReturnedClass()).getPropertyType(properties[i + 1]);
}
}
Class<?> returnedClass = propertyType.getReturnedClass();
if(propertyType.isCollectionType()) {
try {
Field field = entityType.getDeclaredField(property);
ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
returnedClass = (Class<?>) parameterizedType.getActualTypeArguments()[0];
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if(propertyType.isAssociationType()) {
CrudTable crudTableAnnotation = (CrudTable) returnedClass.getAnnotation(CrudTable.class);
if(crudTableAnnotation != null) {
boolean subcriteriaFound = false;
for(Subcriteria sc : subcriterias) {
if(sc.getPath().equals(property)) {
criteria = sc;
subcriteriaFound = true;
break;
}
}
if(!subcriteriaFound) {
criteria = criteria.createCriteria(property);
subcriterias.add((Subcriteria) criteria);
}
property = crudTableAnnotation.filteringPropertyName();
propertyType = sessionFactory.getCurrentSession().getSessionFactory().getClassMetadata(returnedClass).getPropertyType(property);
} else {
throw new RuntimeException("Entity class " + getClassMetadata().getEntityName() + " doesn't declare a filtering property name (no CrudTable annotation present).");
}
}
StringContainerFilter sf = new StringContainerFilter(property, filter.filterString, filter.filterString2, filter.ignoreCase, filter.onlyMatchPrefix);
Criterion criterion = getCustomRestriction(sf, propertyType.getReturnedClass());
if(criterion != null) {
criteria.add(criterion);
}
while(criteria.getClass().equals(Subcriteria.class)) {
criteria = ((Subcriteria) criteria).getParent();
}
}
}
return criteria;
}
/**
* Returns a Restriction accordingly to the given Filter.
* @param Filter to construct the Restriction object.
* @param clazz property class.
* @return a Restriction object for the given Filter.
*/
public Criterion getCustomRestriction(StringContainerFilter filter, Class<?> clazz) {
Criterion criterion = null;
if(clazz.equals(String.class)) {
if (filter.ignoreCase) {
criterion = Restrictions.ilike(filter.getPropertyId().toString(), filter.filterString, filter.onlyMatchPrefix ? MatchMode.START : MatchMode.ANYWHERE);
} else {
criterion = Restrictions.like(filter.getPropertyId().toString(), filter.filterString, filter.onlyMatchPrefix ? MatchMode.START : MatchMode.ANYWHERE);
}
} else if(clazz.equals(Integer.class)) {
try {
criterion = Restrictions.eq(filter.getPropertyId().toString(), new Integer(filter.filterString));
} catch (NumberFormatException e) {
}
} else if(clazz.equals(Long.class)) {
try {
criterion = Restrictions.eq(filter.getPropertyId().toString(), new Long(filter.filterString));
} catch (NumberFormatException e) {
}
} else if(clazz.equals(Double.class)) {
try {
criterion = Restrictions.eq(filter.getPropertyId().toString(), new Double(filter.filterString));
} catch (NumberFormatException e) {
}
} else if(clazz.equals(Float.class)) {
try {
criterion = Restrictions.eq(filter.getPropertyId().toString(), new Double(filter.filterString));
} catch (NumberFormatException e) {
}
} else if(clazz.equals(BigDecimal.class)) {
try {
criterion = Restrictions.eq(filter.getPropertyId().toString(), new BigDecimal(filter.filterString));
} catch (NumberFormatException e) {
}
} else if(clazz.equals(Date.class)) {
try {
Date date1;
Date date2;
if(filter.filterString.isEmpty()) {
date1 = new Date(Long.MIN_VALUE);
} else {
int length = filter.filterString.length() < Utils.getDateTimeFormatPattern().length() ? filter.filterString.length() : Utils.getDateTimeFormatPattern().length();
date1 = new SimpleDateFormat(Utils.getDateTimeFormatPattern().substring(0, length)).parse(filter.filterString);
}
if(filter.filterString2.isEmpty()) {
date2 = Utils.getMaxDate();
} else {
int length = filter.filterString2.length() < Utils.getDateTimeFormatPattern().length() ? filter.filterString2.length() : Utils.getDateTimeFormatPattern().length();
date2 = new SimpleDateFormat(Utils.getDateTimeFormatPattern().substring(0, length)).parse(filter.filterString2);
}
criterion = Restrictions.between(filter.getPropertyId().toString(), date1, date2);
} catch (ParseException e) {
Date date1 = new Date(1);
Date date2 = new Date(2);
// this should reject all results
criterion = Restrictions.between(filter.getPropertyId().toString(), date2 , date1);
}
} else if(clazz.equals(Boolean.class)) {
if(filter.filterString.equalsIgnoreCase(Constants.uiYes) || filter.filterString.equalsIgnoreCase(Constants.uiYes.substring(0, 1)) || filter.filterString.equals("1")) {
criterion = Restrictions.eq(filter.getPropertyId().toString(), true);
} else if (filter.filterString.equalsIgnoreCase(Constants.uiNo) || filter.filterString.equalsIgnoreCase(Constants.uiNo.substring(0, 1)) || filter.filterString.equals("0")) {
criterion = Restrictions.eq(filter.getPropertyId().toString(), false);
} else {
// this should reject all results
criterion = Restrictions.and(Restrictions.eq(filter.getPropertyId().toString(), true), Restrictions.eq(filter.getPropertyId().toString(), false));
}
}
return criterion;
}
public void refresh() {
clearInternalCache();
fireItemSetChange();
}
}